<?php

/**
 * Bootstrap.php
 *
 * Holds class Bootstrap
 *
 * @package Application
 */

/**
 * Bootstrap
 *
 * Bootstraps application
 *
 * @package Application
 */
class Bootstrap extends Mvc_Controller_Front {

	/**
	 * Constructor
	 *
	 * @return void
	 */
	public function __construct() {
		parent::__construct();

		// Register autoloaders
		spl_autoload_register(array(__CLASS__, 'autoloadClass'));
		spl_autoload_register(array(__CLASS__, 'autoloadModel'));
		
		Benchmark::instance();

		// Create config
		$config = new Config();
		$config->import(APP . 'config/common.php')
		       ->import(APP . 'config/database.php');
		try{// Create database
			$dsn = $config->get('database')->get('type') . ':dbname=' . $config->get('database')->get('name') . ';host=' . $config->get('database')->get('host');
			$db = new Database($dsn, $config->get('database')->get('user'), $config->get('database')->get('pass'));
		}catch(PDOException $e){//force local host
			die($e);
//			$dsn = $config->get('database')->get('type') . ':dbname=' . $config->get('database')->get('name') . ';host=localhost';
//			$db = new Database($dsn, $config->get('database')->get('user'), $config->get('database')->get('pass'));
		}
		$config->remove('database');//unset

		// Create language
		$language = new Language();
		$language->setLanguagePath(APP . 'lang/' . $config->get('language') . '/');

		// Create log
		$log = new Log($this->_getRequest(), APP . 'logs/common.txt');

		// Set routes
		$routes = new Config();
		$routes->import(APP . 'config/routes.php');

		// Set router paths
		$this->_getRouter()->setBasePath($config->get('base'))
		                   ->setModulePath(APP . 'modules/')
		                   ->setSitePath($config->get('url'));

		// Set default route
		try {
			$defaultRoute = explode('/', $routes->get('_default'));
			$this->_getRouter()->setDefault(array(
		        'module'     => $defaultRoute[0],
		        'controller' => $defaultRoute[1],
		        'action'     => $defaultRoute[2]
			));

			$routes->remove('=_default=');//unset
		}
		catch(Exception $e) {
			// no default route, do nothing
		}

		// Set custom routes
		$this->_getRouter()->setRoute($routes->export());

		// Set controller context
		$controllerContext = new Mvc_Context_Controller();
		$controllerContext->setConfig($config)
		                  ->setDb($db)
		                  ->setLanguage($language)
		                  ->setLog($log)
		                  ->setRequest($this->_getRequest())
		                  ->setRouter($this->_getRouter());

		// Pass both to dispatcher
		$this->_getDispatcher()->setControllerContext($controllerContext);
	}

	/**
	 * Runs application
	 *
	 * @see Mvc_Controller_Front::run()
	 * @return Mvc_Response|string
	 */
	public function run() {
		// Import error routes
		$config = new Config();
		$config->import(APP . 'config/error.php');

		
		try {
			$response = parent::run();
			
			if($response instanceof Mvc_Response) {
				
				switch($response->getStatus()){
					case 401:return $this->getErrorResponse(
								$this->setErrorRequest($config,401),
								$config,
								401);
						break;
					
					case 200:return $response;
						break;
				}
			}
			
			return $this->getErrorResponse(
				$this->setErrorRequest($config,404),
				$config,
				404);
			
		}
		catch(Exception $e) {//exception occured, render 500
			try {
				
				return $this->getErrorResponse(
					$this->setErrorRequest($config,500)->setParam('exception', $e),
					$config,
					500);
			}
			catch(Exception $e) {//exception occured, render plain text
				if(DEVELOPMENT) {
					echo '<pre>';print_r($e);echo '</pre>';
				}

				header('HTTP/1.1 500 Internal Server Error');
				return '500 Internal Server Error';
			}
		}
	}
	
	public function returnRun($response){
		
	}
	
	/**
	 * @param Config $config
	 * @param int $errorNR
	 * @return Mvc_Request
	 */
	public function setErrorRequest(Config $config, $errorNR){
		$this->_getRequest()->setModule($config->get($errorNR)->get('module'))
			->setController($config->get($errorNR)->get('controller'))
			->setAction($config->get($errorNR)->get('action', $errorNR));
		return $this->_getRequest();
	}
	
	/**
	 *	@param Mvc_Request $request
	 *	@param Config $config
	 *	@param int $errorNR
	 *	@return Mvc_Response
	 */
	public function getErrorResponse(Mvc_Request $request, Config $config, $errorNR){
		$response = $this->_getDispatcher()->dispatch(APP . 'modules/' . $request->getModule() . DIRECTORY_SEPARATOR . $request->getController() . '.php');

		if($response instanceof Mvc_Response)	return $response;

		//Not found, render manual response
		$response = new Mvc_Response();
		return $response->setStatus($errorNR)->setBody($errorNR . $config->get($errorNR)->get('manual'));
	}

	/**
	 * Autoloads application classes
	 *
	 * @param string $class
	 * @return boolean
	 */
	public static function autoloadClass($class) {
		$file = rtrim(dirname(__FILE__), '\\/') . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
		if(file_exists($file)) {
			require_once $file;
			return true;
		}
		return false;
	}

	/**
	 * Autoloads application model classes
	 *
	 * @param string $class
	 * @return boolean
	 */
	public static function autoloadModel($class) {
		// Get paths (once)
		static $modelPath;
//		if(!$modelPath) {
//			$modelPath = glob(APP . 'modules/*');
//		}

		$modelPath = APP . 'models' . DIRECTORY_SEPARATOR;

		// Search model
//		foreach($modelPath as $path) {
			$file = rtrim($modelPath, '\\/') . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
			if(file_exists($file)) {
				
				require_once $file;
				return true;
			}
//		}
		return false;
	}

}
